//
//  CommandClassesPrivate.h
//  Part of Z-Way.C library
//
//  Created by Alex Skalozub on 2/1/12.
//  Based on Z-Way source code written by Christian Paetz and Poltorak Serguei
//
//  Copyright (c) 2012 Z-Wave.Me
//  All rights reserved
//  info@z-wave.me
//
//  This source file is subject to the terms and conditions of the
//  Z-Wave.Me Software License Agreement which restricts the manner
//  in which it may be used.
//

#ifndef zway_command_classes_private_h
#define zway_command_classes_private_h

#include "ZStreamStoragePrivate.h"

#ifdef __cplusplus
extern "C" {
#endif
extern const ZCommandClass ccNoOperation;
extern const ZCommandClass ccBasic;
extern const ZCommandClass ccWakeup;
extern const ZCommandClass ccVersion;
extern const ZCommandClass ccBattery;
extern const ZCommandClass ccManufacturerSpecific;
extern const ZCommandClass ccConfiguration;
extern const ZCommandClass ccSensorBinary;
extern const ZCommandClass ccSensorMultilevel;
extern const ZCommandClass ccSensorConfiguration;
extern const ZCommandClass ccAssociation;
extern const ZCommandClass ccMultiChannelAssociation;
extern const ZCommandClass ccMeter;
extern const ZCommandClass ccSwitchAll;
extern const ZCommandClass ccSwitchBinary;
extern const ZCommandClass ccSwitchMultilevel;
extern const ZCommandClass ccSwitchColor;
extern const ZCommandClass ccMultiCmd;
extern const ZCommandClass ccMultiChannel;
extern const ZCommandClass ccNodeNaming;
extern const ZCommandClass ccThermostatSetPoint;
extern const ZCommandClass ccThermostatSetBack;
extern const ZCommandClass ccThermostatMode;
extern const ZCommandClass ccThermostatFanMode;
extern const ZCommandClass ccThermostatFanState;
extern const ZCommandClass ccThermostatOperatingState;
extern const ZCommandClass ccAlarmSensor;
extern const ZCommandClass ccSecurityS2;
extern const ZCommandClass ccSecurity;
extern const ZCommandClass ccDoorLock;
extern const ZCommandClass ccUserCode;
extern const ZCommandClass ccTransportService;
extern const ZCommandClass ccTime;
extern const ZCommandClass ccTimeParameters;
extern const ZCommandClass ccClock;
extern const ZCommandClass ccSceneActivation;
extern const ZCommandClass ccSceneControllerConf;
extern const ZCommandClass ccSceneActuatorConf;
extern const ZCommandClass ccClimateControlSchedule;
extern const ZCommandClass ccDoorLockLogging;
extern const ZCommandClass ccProtection;
extern const ZCommandClass ccIndicator;
extern const ZCommandClass ccScheduleEntryLock;
extern const ZCommandClass ccApplicationStatus;
extern const ZCommandClass ccMeterTableMonitor;
extern const ZCommandClass ccAlarm;
extern const ZCommandClass ccFirmwareUpdate;
extern const ZCommandClass ccPowerLevel;
extern const ZCommandClass ccZWavePlusInfo;
extern const ZCommandClass ccCRC16;
extern const ZCommandClass ccAssociationGroupInformation;
extern const ZCommandClass ccDeviceResetLocally;
extern const ZCommandClass ccSchedule;
extern const ZCommandClass ccCentralScene;
extern const ZCommandClass ccControllerReplication;
extern const ZCommandClass ccProprietary;
extern const ZCommandClass ccMeterPulse;
extern const ZCommandClass ccBarrierOperator;
extern const ZCommandClass ccHail;
extern const ZCommandClass ccSimpleAVControl;
extern const ZCommandClass ccSoundSwitch;
extern const ZCommandClass ccEntryControl;
extern const ZCommandClass ccSupervision;
extern const ZCommandClass ccInclusionController;
extern const ZCommandClass ccUserCredential;
extern const ZCommandClass ccRemoteCLI;
#ifdef __cplusplus
}
#endif

// not to be exposed to user, since the lib handles MultiCmd internally
ZWError _zway_cc_multicmd_encapsulate(ZWay zway, ZWNODE node_id, ZWBYTE instance_id, ZJobList jobs, ZJob *pjob);

// not to be exposed to user, since the lib handles MultiChannel internally
ZWError _zway_cc_multichannel_encapsulate(const ZWay zway, const ZWNODE node_id, const ZWBYTE my_instance_id, const ZWBYTE endpoint, ZWBYTE *const p_length, ZWBYTE *const data);
ZWError _zway_cc_multichannel_multicast_encapsulate(ZWay zway, ZWNODE node_id, ZWBYTE instance_id, ZJobList jobs, ZJob *pjob);

// not to be exposed to user, since the lib handles CRC16 internally
ZWError _zway_cc_crc16_encapsulate(const ZWay zway, const ZWNODE node_id, ZWBYTE length, ZWBYTE *const data);
void _zway_cc_crc16_recalculate(const ZJob job);
static inline ZWBYTE _zway_cc_crc16_encapsulate_offset(void)
{
    return 2;
};
static inline ZWBYTE _zway_cc_crc16_encapsulate_size(void)
{
    return 4;
};

// not to be exposed to user, since the lib handles Supervision internally
void _zway_cc_supervision_encapsulate(const ZWBYTE length, ZWBYTE *const data);
void _zway_cc_supervision_expected_reply(const ZJob job);
void _zway_cc_supervision_fill_session(const ZWay zway, const ZJob job);
static inline ZWBYTE _zway_cc_supervision_encapsulate_offset(void)
{
    return 4;
};
static inline ZWBYTE _zway_cc_supervision_encapsulate_size(void)
{
    return 4;
};

static inline ZWBYTE _zway_cc_payload_size_mc_value(void)
{
    return 4;
};

// not to be exposed to user, since the lib handles Transport Service internally
ZWError _zway_cc_transport_service_encapsulate(ZWay zway, ZCommand command, ZWBYTE length, const ZWBYTE *data, ZJob job);

// query Version Command Class Get for a CC
ZWError _zway_cc_version_add_cc(ZWay zway, ZCommand command0Version, ZCommand command);

#define SECURITY_INCLUSION_TIMEOUT 10.0f
#define SIS_WAITING_FOR_INCLUSION_CONTROLLER_TIMEOUT 12.0f

ZWBOOL _zway_cc_security_shall_not_encapsulate(ZWay zway, ZDevice device, ZWBYTE command);

ZWError _zway_cc_security_send_nonce(ZWay zway, ZDevice device);

ZWError _zway_cc_security_abandon(ZWay zway, ZDevice device);

// S2 bootstraping
ZWError _zway_cc_inclusion_controller_initiate_new(ZWay zway, ZWNODE nodeId);
ZWError _zway_cc_inclusion_controller_initiate_replace(ZWay zway, ZWNODE nodeId);
ZWError _zway_cc_inclusion_controller_complete_inclusion_success(ZWay zway);
ZWError _zway_cc_inclusion_controller_complete_inclusion_failed(ZWay zway);
ZWError _zway_cc_inclusion_controller_complete_s0_success(ZWay zway);
ZWError _zway_cc_inclusion_controller_complete_s0_failed(ZWay zway);

// Mapping from SET-like commands to Controller CCs
ZWError _map_to_controller(ZWay zway, ZWNODE src_node_id, ZWBYTE src_instance_id, ZWBYTE dst_instance_id, ZWBYTE cc_id, ZWBYTE length, const ZWBYTE *data);

ZCommand _zway_get_controller_cmd(ZWay zway, ZWBYTE instance_id, ZWBYTE cc_id);

ZWError zway_cc_nop_send(ZWay zway, ZWNODE node_id, ZWBYTE instance_id, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWError zway_cc_device_reset_locally_notify(ZWay zway, ZWNODE node_id, ZWBYTE instance_id, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

// notify the sender that we have rejected the request
ZWError _zway_cc_application_reject_request(ZWay zway, ZWNODE node_id, ZWBYTE instance_id, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

#define POWERLEVEL_TEST_NODE_REPORT_ZW_TEST_FAILED       0x00
#define POWERLEVEL_TEST_NODE_REPORT_ZW_TEST_SUCCESS      0x01
#define POWERLEVEL_TEST_NODE_REPORT_ZW_TEST_INPROGRESS   0x02

ZWError _zway_cc_power_level_test_node_report(ZWay zway, ZCommand command, ZWNODE nodeId, ZWBYTE status, uint16_t successfulCount, ZJobCustomCallback successCallback, ZJobCustomCallback failureCallback, void* callbackArg);

ZWBOOL _zway_cc_association_group_information_is_reporting(ZWay zway, ZCommand command, ZWBYTE group_id);
ZWBOOL _zway_cc_association_is_group_zero_size(ZWay zway, ZCommand command, ZWBYTE group_id);

#define CELSIUS 0
#define FAHRENHEIT 1

ZWBYTE _zway_cc_get_locale_scale(ZWay zway);

float _f2c(float f);
float _c2f(float c);
int _bytesToInt(const ZWBYTE *bytes, ZWBYTE size);
float _adjustedFixedPrecisionValue(int intValue, ZWBYTE precision, ZWBYTE scale, ZWBYTE localScale, ZWBOOL temperature);

#define CALL_LOCKED(method) \
    zdata_acquire_lock(ZDataRoot(zway)); \
    ZWError r = method; \
    zdata_release_lock(ZDataRoot(zway)); \
    return r

#define CALL_LOCKED2(method1, method2) \
    zdata_acquire_lock(ZDataRoot(zway)); \
    ZWError r = method1; \
    if (r == NoError) \
        r = method2; \
    zdata_release_lock(ZDataRoot(zway)); \
    return r

#define CHECK_REPLY_MAX_BUFFER 7

#define CHECK_REPLY1_BUF(expected_reply_payload, expected_reply_payload_value) \
    expected_reply_payload[0] = command->id; \
    expected_reply_payload[1] = expected_reply_payload_value; \
    ZWBOOL solicited = _zway_reply_handle(zway, command->instance->device->id, command->instance->id, 2, expected_reply_payload); \
    (void)solicited;

#define CHECK_REPLY2_BUF(expected_reply_payload, expected_reply_payload_value1, expected_reply_payload_value2) \
    expected_reply_payload[0] = command->id; \
    expected_reply_payload[1] = expected_reply_payload_value1; \
    expected_reply_payload[2] = expected_reply_payload_value2; \
    ZWBOOL solicited = _zway_reply_handle(zway, command->instance->device->id, command->instance->id, 3, expected_reply_payload); \
    (void)solicited;

#define CHECK_REPLY3_BUF(expected_reply_payload, expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3) \
    expected_reply_payload[0] = command->id; \
    expected_reply_payload[1] = expected_reply_payload_value1; \
    expected_reply_payload[2] = expected_reply_payload_value2; \
    expected_reply_payload[3] = expected_reply_payload_value3; \
    ZWBOOL solicited = _zway_reply_handle(zway, command->instance->device->id, command->instance->id, 4, expected_reply_payload); \
    (void)solicited;

#define CHECK_REPLY4_BUF(expected_reply_payload, expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3, expected_reply_payload_value4) \
    expected_reply_payload[0] = command->id; \
    expected_reply_payload[1] = expected_reply_payload_value1; \
    expected_reply_payload[2] = expected_reply_payload_value2; \
    expected_reply_payload[3] = expected_reply_payload_value3; \
    expected_reply_payload[4] = expected_reply_payload_value4; \
    ZWBOOL solicited = _zway_reply_handle(zway, command->instance->device->id, command->instance->id, 5, expected_reply_payload); \
    (void)solicited;

#define CHECK_REPLY5_BUF(expected_reply_payload, expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3, expected_reply_payload_value4, expected_reply_payload_value5) \
    expected_reply_payload[0] = command->id; \
    expected_reply_payload[1] = expected_reply_payload_value1; \
    expected_reply_payload[2] = expected_reply_payload_value2; \
    expected_reply_payload[3] = expected_reply_payload_value3; \
    expected_reply_payload[4] = expected_reply_payload_value4; \
    expected_reply_payload[5] = expected_reply_payload_value5; \
    ZWBOOL solicited = _zway_reply_handle(zway, command->instance->device->id, command->instance->id, 6, expected_reply_payload); \
    (void)solicited;

#define CHECK_REPLY6_BUF(expected_reply_payload, expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3, expected_reply_payload_value4, expected_reply_payload_value5, expected_reply_payload_value6) \
    expected_reply_payload[0] = command->id; \
    expected_reply_payload[1] = expected_reply_payload_value1; \
    expected_reply_payload[2] = expected_reply_payload_value2; \
    expected_reply_payload[3] = expected_reply_payload_value3; \
    expected_reply_payload[4] = expected_reply_payload_value4; \
    expected_reply_payload[5] = expected_reply_payload_value5; \
    expected_reply_payload[6] = expected_reply_payload_value6; \
    ZWBOOL solicited = _zway_reply_handle(zway, command->instance->device->id, command->instance->id, 7, expected_reply_payload); \
    (void)solicited;

#define CHECK_REPLY1(expected_reply_payload_value) \
    ZWBYTE expected_reply_payload[2]; \
    CHECK_REPLY1_BUF(expected_reply_payload, expected_reply_payload_value)

#define CHECK_REPLY2(expected_reply_payload_value1, expected_reply_payload_value2) \
    ZWBYTE expected_reply_payload[3]; \
    CHECK_REPLY2_BUF(expected_reply_payload, expected_reply_payload_value1, expected_reply_payload_value2)

#define CHECK_REPLY3(expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3) \
    ZWBYTE expected_reply_payload[4]; \
    CHECK_REPLY3_BUF(expected_reply_payload, expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3)

#define CHECK_REPLY4(expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3, expected_reply_payload_value4) \
    ZWBYTE expected_reply_payload[5]; \
    CHECK_REPLY4_BUF(expected_reply_payload, expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3, expected_reply_payload_value4)

#define CHECK_REPLY5(expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3, expected_reply_payload_value4, expected_reply_payload_value5) \
    ZWBYTE expected_reply_payload[6]; \
    CHECK_REPLY5_BUF(expected_reply_payload, expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3, expected_reply_payload_value4, expected_reply_payload_value)

#define CHECK_REPLY6(expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3, expected_reply_payload_value4, expected_reply_payload_value5, expected_reply_payload_value6) \
    ZWBYTE expected_reply_payload[7]; \
    CHECK_REPLY6_BUF(expected_reply_payload, expected_reply_payload_value1, expected_reply_payload_value2, expected_reply_payload_value3, expected_reply_payload_value4, expected_reply_payload_value5, expected_reply_payload_value6)

#define WAIT_UNSOLICITED_REPORT 2.0

ZWError _zway_command_classes_default_not_implemented(ZWay zway, ZCommand command, ZWBYTE cmd);

ZWEXPORT_PRIVATE ZWError _zway_cc_firmware_update_perform_srv(_ZStreamStoragUpdateResult_t *const result, const ZWay zway, const ZWNODE node_id, const ZWBYTE firmwareTarget);

ZWError _zway_cc_version_get(const ZWay zway, const ZWNODE node_id);

#endif
